import * as colors from '@material-ui/core/colors'
import { random } from 'lodash'
import { createEnumFactory } from '@/utils/fridayClub/enumUtil'

//  >>>>>>>>>>>>>> color >>>>>>>>>>>>>>>
function allColor() {
  return Object.values(colors)
    .reduce((acc, cur) => acc.concat(Object.values(cur)), Array.of())
    .filter(v => !['#000', '#fff'].includes(v))
}

const allColors = allColor()

function getRandomColor() {
  return allColors[random(0, allColors.length - 1)]
  // |> debugLogger()
}

//  >>>>>>>>>>>>>> color >>>>>>>>>>>>>>>

//  >>>>>>>>>>>>>> transfer >>>>>>>>>>>>>>>

export const directionEnum = createEnumFactory([
  { label: 'top', value: 1 },
  { label: 'bottom', value: 2 },
  { label: 'left', value: 4 },
  { label: 'right', value: 8 },
  { label: 'none', value: 16 }
])

const barcodeDirectionOptions = [
  { label: '上', value: 1 },
  { label: '下', value: 2 },
  { label: '左', value: 4 },
  { label: '右', value: 8 },
  { label: '无', value: 16 }
]

export const directionEngChineseEnum = createEnumFactory([
  { label: 'none', value: '无条码' },
  { label: 'top', value: '上方' },
  { label: 'right', value: '右方' },
  { label: 'bottom', value: '下方' },
  { label: 'left', value: '左方' }
])
//  >>>>>>>>>>>>>> transfer >>>>>>>>>>>>>>>
export const lastBarCodePos = {
  top: {
    0: 'top',
    90: 'right',
    180: 'bottom',
    270: 'left'
  },
  right: {
    0: 'right',
    90: 'bottom',
    180: 'left',
    270: 'top'
  },
  bottom: {
    0: 'bottom',
    90: 'left',
    180: 'top',
    270: 'right'
  },
  left: {
    0: 'left',
    90: 'top',
    180: 'right',
    270: 'bottom'
  },
  none: {
    0: 'none',
    90: 'none',
    180: 'none',
    270: 'none'
  }
}

//  >>>>>>>>>>>>>> grid data >>>>>>>>>>>>>>>

/**
 * @deprecated
 * @link GridItemVO
 */
class GridItem {
  constructor({
                x = 0, y = 0, w = 100, h = 100, key,
                bc = getRandomColor(), rotateAngle = 0, barcodePos = 16,
                name = '', bSize = 20, bfSize = 20, bh = 6,
                allowRotate = false, boardId = 0, detailId = 0
              } = {}) {
    this.x = x
    this.y = y
    this.w = w
    this.h = h
    this.key = key
    this.rotateAngle = rotateAngle
    this.barcodePos = barcodePos // directionEnum[barcodePos]
    this.name = name
    this.bSize = bSize
    this.bfSize = bfSize
    this.bh = bh
    this.allowRotate = allowRotate
    this.boardId = boardId
    this.detailId = detailId
    this.bc = bc
  }
}

//  alias
const GridItemVO = GridItem

class GridItemPO {
  constructor({
                x, y, w, h, key, rotateAngle, barcodePos,
                name, bSize, bfSize, bh, allowRotate, boardId, detailId
              } = {}) {
    this.BoardModelDetailIId = detailId
    this.BoardModelID = boardId
    this.PhotoIndex = key

    console.log(barcodePos,rotateAngle);

    const computedBarcodePos = directionEnum[lastBarCodePos[directionEnum[barcodePos]][rotateAngle]]
    // console.log('computedBarcodePos ',computedBarcodePos);

    this.RemarkHeight = bh
    this.RemarkDirection = computedBarcodePos  //  directionEnum[barcodePos]  barcodePos
    this.RemarkCodeSize = bSize
    this.RemarkFontSize = bfSize

    this.RotateDegrees = rotateAngle
    this.AllowRotate = !!rotateAngle

    this.locationType = 1
    this.Formatflag = '1'

    this.X = x
    this.Y = y
    this.Width = w
    this.Height = h

  }
}

//  >>>>>>>>>>>>>> color >>>>>>>>>>>>>>>

const baseStyle = {
  position: 'absolute',
  background: '#000000'
}
const tbwh = {
  width: '100%',
  height: '10%'
}
const lrwh = {
  width: '10%',
  height: '100%'
}

/**
 * @param pos [top ,left ,right ,bottom]
 */
const generateBarcodePosStyle = (pos) => {
  if (pos === 'top') {
    return Object.assign({}, baseStyle, tbwh, {
      top: 0
    })
  } else if (pos === 'right') {
    return Object.assign({}, baseStyle, lrwh, {
      right: 0
    })
  } else if (pos === 'bottom') {
    return Object.assign({}, baseStyle, tbwh, {
      bottom: 0
    })
  } else if (pos === 'left') {
    return Object.assign({}, baseStyle, lrwh, {
      left: 0
    })
  }
  return {}
}

//  >>>>>>>>>>>>>> enums >>>>>>>>>>>>>>>

const rotateAngleList = [
  { value: '0', label: '0°' },
  { value: '90', label: '90°' },
  { value: '180', label: '180°' },
  { value: '270', label: '270°' }
]

const boardModeList = [
  { value: 0, label: '普通' },
  { value: 1, label: '自由' }
]
//  >>>>>>>>>>>>>> color >>>>>>>>>>>>>>>

//  >>>>>>>>>>>>>> Rectangle utils >>>>>>>>>>>>>>>
class Rectangle {
  static transferXYWH2LTRB({ x, y, w, h, ...rest } = {}) {
    return { l: x, t: y, r: w + x, b: h + y, ...rest }
  }

  static transferLTRB2XYWH({ l, t, r, b, ...rest } = {}) {
    return { x: l, y: t, w: r - l, h: b - t, ...rest }
  }

  static getCenterBy() {
  }
}

//  把当前的多个元素转换为一个整体
//  x, y, w ,h
//  L T 是最小的 , R B 是最大的
//  传入 l t r b
//  输出 l t r b
/**
 * 获取多个元素的boundingRect,如果只有一个元素或者是一个对象直接返回自己
 * 否则
 * @param gridList
 * @returns {*}
 */
const transformMultiGrid2Sole = (gridList) => {
  if (Array.isArray(gridList)) {
    return gridList.length === 1 ? gridList[0] : gridList.reduce((prev, { l, t, r, b }) => {
      // const { l, t, r, b } = Rectangle.transferXYWH2LTRB({ x, y, w, h })
      return {
        l: prev.l ? Math.min(prev.l, l) : l,
        t: prev.t ? Math.min(prev.t, t) : t,
        r: Math.max(prev.r, r),
        b: Math.max(prev.b, b)
      }
    }, { l: 0, t: 0, r: 0, b: 0 })
  }
  return gridList
}

/**
 * @param LTRBList 全部需要就算的碰撞元素
 * @param relativeBounding  当前需要移动的元素
 * @param paintCloth  限制的范围
 * @returns {*}
 */
const getCanMoveSpaceByCurrentAndPaintCloth = (LTRBList, relativeBounding, paintCloth) => {
  const { w, h } = paintCloth
  const { l, t, r, b } = relativeBounding
  return LTRBList.reduce((p, c) => {
    const getMaxInLimit = (limit, ...compares) => {
      const max = Math.max(...compares)
      return max > limit ? Math.min(...compares) : max
    }
    const getMinInLimit = (limit, ...compares) => {
      const min = Math.min(...compares)
      return min < limit ? Math.max(...compares) : min
    }
    return {
      //  计算左边的障碍物,取小于当前块的L并且最接近L的那个元素的R作为baseL,如果没有则为0
      l: getMaxInLimit(l, p.l, c.r),
      //  同上
      t: getMaxInLimit(t, p.t, c.b),
      //  计算右边的障碍物,取最小的但大于R的那个元素的L作为基准线 如果没有则为画布的w,
      r: getMinInLimit(r, p.r, c.l),
      //  同上
      b: getMinInLimit(b, p.b, c.t)
    }
  }, { l: 0, t: 0, r: w, b: h })
}

const calcCenterBounding = (canMoveBounding, relativeBounding) => {
  const { l, t, r, b } = canMoveBounding
  const cb = relativeBounding
  const lb = (((r - l) - (cb.r - cb.l)) / 2) + l
  const tb = (((b - t) - (cb.b - cb.t)) / 2) + t
  return { lb, tb }
}

//  l,t,r,b
const calcMovedGridList = (nHGridList, relativeBounding, centerBounding, mode) => {
  // const { l, t, r, b } = relativeBounding
  const rb = relativeBounding
  const { lb: clb, tb: ctb } = centerBounding
  //  mapping
  return nHGridList.map(g => {
    const base = {
      [MediateMode.horizonMediate]: () => ({
        l: g.l - rb.l + clb,
        r: g.r - rb.l + clb
      }),
      [MediateMode.verticalMediate]: () => ({
        t: g.t - rb.t + ctb,
        b: g.b - rb.t + ctb
      })
    }
    const f = {
      ...base,
      [MediateMode.allMediate]: () => ({
        ...base[MediateMode.horizonMediate](),
        ...base[MediateMode.verticalMediate]()
      })
    }
    return {
      ...g, ...f[mode]()
    }
  })
}

class MediateMode {
  static verticalMediate = '$@_verticalMediate'
  static horizonMediate = '$@_horizonMediate'
  static allMediate = '$@_allMediate'
}

//  传参的类型
class GridParamType {

}

/**
 *  把list分类,一类是要被移动的,另一类是其他的元素
 *  最大和最小都有可能取画布的宽和高
 *  change to  the plugins mode
 * @param gridList  [Object|Array[0-n]] 全部的grid (默认模式 X Y W H)
 * @param needHandleGridList  需要移动的grid
 * @param paintCloth  实际画布大小
 * @param opts  Object 配置对象
 * @returns {*} 移动之后的gridList (返回 X Y W H)
 */
const gridToMediate = (gridList, needHandleGridList, paintCloth, opts = {}) => {
  const { mode, key = 'key' } = opts

  const nHGridList = autoHandleArr(
    Array.isArray(needHandleGridList) ? needHandleGridList : [needHandleGridList],
    v => Rectangle.transferXYWH2LTRB(v)
  )

  const LTRBList = autoHandleArr(gridList, v => Rectangle.transferXYWH2LTRB(v))
  console.log('nHGridList %o', nHGridList)
  console.log('LTRBList %o', LTRBList)

  //  我们只需要计算出用户给定需要移动元素的bounding
  const relativeBounding = transformMultiGrid2Sole(nHGridList)
  console.log('relativeBounding %o', relativeBounding)

  //  根据当前的位置来算出可以移动到的上下左右的距离
  const canMoveBounding = getCanMoveSpaceByCurrentAndPaintCloth(
    [...LTRBList, ...nHGridList], relativeBounding, paintCloth
  )
  console.log('canMoveBounding %o', canMoveBounding)

  //  根据 当前位置 和 可移动位置 来算出如果当前元素居中,那么最左边的线和最上边的线的位置在哪
  const centerBounding = calcCenterBounding(canMoveBounding, relativeBounding)
  console.log('centerBounding %o', centerBounding)

  //  把当前的所有相对于 relativeBounding 的 listGrid 来移动到 centerBounding 位置
  const movedGridList = calcMovedGridList(nHGridList, relativeBounding, centerBounding, mode)
  console.log('movedGridList %o', movedGridList)

  //  把原有的移动之后的元素过滤掉,之后放入新的元素
  const keys = nHGridList.map(g => g[key])
  const immovabilityGrid = LTRBList.filter(g => !keys.includes(g[key]))

  return [...immovabilityGrid, ...movedGridList]|>
    (_ => autoHandleArr(_, v => Rectangle.transferLTRB2XYWH(v)))
}

const verticalMediate = (gridList, needHandleGridList, paintCloth) =>
  gridToMediate(gridList, needHandleGridList, paintCloth, { mode: MediateMode.verticalMediate })

const horizonMediate = (gridList, needHandleGridList, paintCloth) =>
  gridToMediate(gridList, needHandleGridList, paintCloth, { mode: MediateMode.horizonMediate })

const allMediate = (gridList, needHandleGridList, paintCloth) =>
  gridToMediate(gridList, needHandleGridList, paintCloth, { mode: MediateMode.allMediate })

//  >>>>>>>>>>>>>> Rectangle utils >>>>>>>>>>>>>>>

//  >>>>>>>>>>>>>> common utils >>>>>>>>>>>>>>>

function autoHandleArr(execObj, execFn) {
  if (Array.isArray(execObj)) {
    return execObj.map(execFn)
  }
  return execFn(execObj)
}

//  >>>>>>>>>>>>>> common utils >>>>>>>>>>>>>>>

export {
  getRandomColor, GridItem, GridItemPO, generateBarcodePosStyle,
  rotateAngleList, barcodeDirectionOptions, boardModeList, GridItemVO, Rectangle,
  verticalMediate, horizonMediate, allMediate, autoHandleArr
}
